package ru.volgogradetzzz.text 
{
	//--------------------------------------
	// Imports
	//--------------------------------------
	
	import flash.display.Graphics;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.text.engine.BreakOpportunity;
	import flash.text.engine.ElementFormat;
	import flash.text.engine.FontDescription;
	import flash.text.engine.FontLookup;
	import flash.text.engine.FontPosture;
	import flash.text.engine.FontWeight;
	import flash.text.engine.RenderingMode;
	import flash.text.engine.TextBaseline;
	import flash.text.engine.TextBlock;
	import flash.text.engine.TextElement;
	import flash.text.engine.TextLine;
	
	//--------------------------------------
	// Class description
	//--------------------------------------
		
	/**
	 * VSimpleText contain only one single line. Text can set it's width automatically if autoWidth set to true,
	 * in other case text is trunkated if string width is greater then explicitly setted width. Text can be formatted.
	 * Whole text change it's style when new format applied.
	 * 
	 * @author Volgogradetzzz
	 */
	public class VSimpleText extends Sprite implements IFTEVText
	{
		//--------------------------------------
		// Private fields
		//--------------------------------------
		
		/**
		 * Text control width.
		 */
		private var _w:Number = 100;
		/**
		 * Allows to VSimpleText instance to 'grow' or 'shrink' automatically in horizontal direction.
		 */
		private var _autoWidth:Boolean = false;
		/**
		 * Text to display.
		 */
		private var _text:String = '';
		/**
		 * Array of lines.
		 */
		private var _linesCont:Sprite = new Sprite();
		/**
		 * Shape for correct width/height getting
		 */
		private var _bg:Shape = new Shape();
		/**
		 * Auxiliary property.
		 */
		private var _textElement:TextElement = new TextElement();
		/**
		 * Auxiliary property.
		 */
		private var _block:TextBlock = new TextBlock(_textElement);
		/**
		 * Delays control updating until 'update' called manually.
		 */
		private var _updateLater:Boolean = false;
		/**
		 * Text format.
		 */
		private var _textFormat:VTextFormat = new VTextFormat();
		/**
		 * Total atoms in text control. Can be less than supplied string because text can be trunkated.
		 */
		protected var _totalAtoms:int;
		
		//--------------------------------------
		// Constructor
		//--------------------------------------
		
		/**
		 * Creates new instance of VSimpleText.
		 */
		public function VSimpleText() 
		{
			var g:Graphics = _bg.graphics;
			g.beginFill(0x000000, 0.0);
			g.drawRect(0, 0, 100, 100);
			g.endFill();
			_bg.width = _w;
			_bg.height = 0;
			addChild(_bg);
			
			addChild(_linesCont);
		}
		
		//--------------------------------------
		// Public methods
		//--------------------------------------
		
		/**
		 * Method recreates lines and set 'updateLater' property to false.
		 * You should call it if 'updateLater' was set to 'true'.
		 */
		public function update():void
		{
			_updateLater = false;
			createLines();
		}
		
		//--------------------------------------
		// Public properties
		//--------------------------------------
		
		/**
		 * Gets or sets text message for VSimpleText instance. VSimpleText can contain only one text line.
		 * If width is not enougth to hold whole string then string is trunkates and property returns
		 * trunkated text. To get full text use 'fullText' property.
		 */
		public function set text(value:String):void
		{
			_text = value;
			
			var fontWeight:String = _textFormat.bold ? FontWeight.BOLD : FontWeight.NORMAL;
			var fontStyle:String = _textFormat.italic ? FontPosture.ITALIC : FontPosture.NORMAL;
			var embedFont:String = _textFormat.embedFont ? FontLookup.EMBEDDED_CFF : FontLookup.DEVICE;
			
			var fontDesc:FontDescription = new FontDescription(_textFormat.font, fontWeight, fontStyle, embedFont, RenderingMode.NORMAL);
			var format:ElementFormat = new ElementFormat(fontDesc, _textFormat.size, _textFormat.color);
			format.breakOpportunity = BreakOpportunity.ANY;
			
			_textElement.text = _text;
			_textElement.elementFormat = format;
			
			if(!_updateLater) createLines();
		}
		/**
		 * @private
		 */
		public function get text():String { return _text.substr(0, _totalAtoms); }
		
		/**
		 * Returns full text. If 'autoWidth' is true then 'text' and 'fullText' are same.
		 */
		public function get fullText():String { return _text };
		
		/**
		 * Gets or sets width of VSimpleText instance. If autoWidth is true then setting width nave no effect
		 * and getting width returns actual width - not width that was setted explicitly.
		 */
		override public function set width(value:Number):void 
		{
			_w = value < 0 ? 0 : value;
			
			if (value < _linesCont.width)
			{
				if(!_updateLater) createLines();
			}
		}
		/**
		 * @private
		 */
		override public function get width():Number { return _w; }
		
		/**
		 * Allows to VSimpleText instance to 'grow' or 'shrink' automatically when new text entered.
		 */
		public function set autoWidth(value:Boolean):void 
		{
			_autoWidth = value;
			
			if(!_updateLater) createLines();
		}
		/**
		 * @private
		 */
		public function get autoWidth():Boolean { return _autoWidth; }
		
		/**
		 * Height is sets automatically based on font size, so setting this property have no effect.
		 */
		override public function get height():Number { return _bg.height; }
		/**
		 * @private
		 */
		override public function set height(value:Number):void 
		{
			//do nothing - height is set automatically based on font size
		}
		
		/**
		 * Sets new text format. VSimpleText supports align, bold, italic, color, font, size and embedFont properties.
		 * 
		 * @param value Instance of VTextFormat that should be applied.
		 */
		public function set textFormat(value:VTextFormat):void
		{
			_textFormat = value;
			text = _text;
		}
		/**
		 * @private
		 */
		public function get textFormat():VTextFormat { return _textFormat; }
		
		/**
		 * Gets characters number in VSimpleText instance. If width is not enougth to hold whole string
		 * then string is trunkates and property returns trunkated text length.
		 * To get full text length use 'fullLength' property.
		 */
		public function get length():int { return _totalAtoms };
		
		/**
		 * Gets characters number of full text in VSimpleText instance. If 'autoWidth' is true
		 * then 'length' and 'fullLength' are same.
		 */
		public function get fullLength():int { return _text.length };
		
		/**
		 * Some of the properties of VSimpleText cause to recreate text lines when that property change. For example,
		 * you can change 'width' and 'textFormat' and for every property text lines would be recreated.
		 * But it would be better to commit all that properties at once and update control only one time.
		 * You can do it by setting 'updateLater' to 'true', changing neccesary properties and than calling 'update' method.
		 */
		public function get updateLater():Boolean { return _updateLater; }
		/**
		 * @private
		 */
		public function set updateLater(value:Boolean):void 
		{
			_updateLater = value;
		}
		
		//--------------------------------------
		// Private methods
		//--------------------------------------
		
		/**
		 * Create lines and aligns them horizontally.
		 * 
		 * @param	group
		 */
		private function createLines():void
		{
			_totalAtoms = 0;
			
			//if lines exists - remove them.
			var numLines:int = _linesCont.numChildren;
			while (--numLines > -1)
			{
				_linesCont.removeChildAt(numLines);
			}
			
			//if text was created before - release it's data for garbage collection.
			if (_block)
			{
				var firstLine:TextLine = _block.firstLine;
				var lastLine:TextLine = _block.lastLine;
				if (firstLine) _block.releaseLines(firstLine, lastLine);
			}
			
			var w:Number = _autoWidth ? 1000000 : _w;
			var line:TextLine = _block.createTextLine(null, w);
			var lastLineDescent:Number = 0;
			
			if (line)
			{
				_linesCont.addChild(line);
				line.y = _linesCont.height;
				lastLineDescent = Math.ceil(line.getBaselinePosition(TextBaseline.DESCENT));
				_totalAtoms += line.atomCount;
				
				if (!_autoWidth)
				{
					if (_textFormat.horizontalAlign == VTextAlign.LEFT)
					{
						line.x = 0;
					}
					else if (_textFormat.horizontalAlign == VTextAlign.CENTER)
					{
						line.x = (_w - line.width) >> 1;
					}
					else if (_textFormat.horizontalAlign == VTextAlign.RIGHT)
					{
						line.x = _w - line.width;
					}
				}
			}
			
			if (_autoWidth)
			{
				_w = _linesCont.width;
			}
			
			_bg.width = _w;
			_bg.height = _linesCont.height + lastLineDescent;
		}
	}
}